//===============================================================================
// Microsoft patterns & practices Enterprise Library Contribution
// Logging Application Block
//===============================================================================

using System;
using System.Collections;
using System.Configuration.Install;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Security.Permissions;

namespace EntLibContrib.Logging.Install
{
	/// <summary>
	/// Logging Installer Class
	/// </summary>
	public class LoggingInstaller : Installer
	{
		private string configPath_;

		/// <summary>
		/// Initializes a new instance of the <see cref="LoggingInstaller"/> class.
		/// </summary>
		/// <param name="configPath">The config path.</param>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2116:AptcaMethodsShouldOnlyCallAptcaMethods")]
		public LoggingInstaller(string configPath)
		{
			if (configPath == null)
				throw new ArgumentNullException("configPath");

			if (!File.Exists(configPath))
				throw new ArgumentException("The configuration file was not found.", "configPath");

			this.configPath_ = configPath;
		}

		/// <summary>
		/// When overridden in a derived class, performs the installation.
		/// </summary>
		/// <param name="stateSaver">An <see cref="T:System.Collections.IDictionary"/> used to save information needed to perform a commit, rollback, or uninstall operation.</param>
		/// <exception cref="T:System.ArgumentException">The <paramref name="stateSaver"/> parameter is null. </exception>
		/// <exception cref="T:System.Exception">An exception occurred in the <see cref="E:System.Configuration.Install.Installer.BeforeInstall"/> event handler of one of the installers in the collection.-or- An exception occurred in the <see cref="E:System.Configuration.Install.Installer.AfterInstall"/> event handler of one of the installers in the collection. </exception>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2116:AptcaMethodsShouldOnlyCallAptcaMethods")]
		public override void Install(IDictionary stateSaver)
		{
			this.AddEventLogInstallers();
			base.Install(stateSaver);
		}

		/// <summary>
		/// When overridden in a derived class, removes an installation.
		/// </summary>
		/// <param name="savedState">An <see cref="T:System.Collections.IDictionary"/> that contains the state of the computer after the installation was complete.</param>
		/// <exception cref="T:System.ArgumentException">The saved-state <see cref="T:System.Collections.IDictionary"/> might have been corrupted. </exception>
		/// <exception cref="T:System.Configuration.Install.InstallException">An exception occurred while uninstalling. This exception is ignored and the uninstall continues. However, the application might not be fully uninstalled after the uninstallation completes. </exception>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2116:AptcaMethodsShouldOnlyCallAptcaMethods")]
		public override void Uninstall(IDictionary savedState)
		{
			this.AddEventLogInstallers();
			base.Uninstall(savedState);
		}

		/// <summary>
		/// Adds the event log installers.
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2116:AptcaMethodsShouldOnlyCallAptcaMethods"), SecurityPermission(SecurityAction.Demand, ControlAppDomain = true)]
		protected virtual void AddEventLogInstallers()
		{
			Assembly currentAssembly = Assembly.GetExecutingAssembly();

			AppDomainSetup domainSetup = new AppDomainSetup();
			domainSetup.ApplicationBase = Path.GetDirectoryName(this.configPath_);
			domainSetup.ConfigurationFile = this.configPath_;

			AppDomain targetAppDomain = AppDomain.CreateDomain("TargetApplicationDomain", null, domainSetup);

			AppDomain.CurrentDomain.AssemblyResolve +=
					delegate(object sender, ResolveEventArgs e)
					{
						if (e.Name == currentAssembly.FullName)
						{
							return currentAssembly;
						}
						throw new InvalidOperationException(string.Format(
								CultureInfo.CurrentCulture,
								"No assembly resolution logic was defined for {0}",
								e.Name));
					};

			LoggingConfigurationLoader configLoader =
					(LoggingConfigurationLoader)targetAppDomain.CreateInstanceAndUnwrap(
					typeof(LoggingConfigurationLoader).Assembly.FullName,
					typeof(LoggingConfigurationLoader).FullName);

			foreach (EventLogConfiguration elc in configLoader.EventLogs)
			{
				EventLogInstaller logInstaller = new EventLogInstaller();
				logInstaller.Log = elc.Log;
				logInstaller.Source = elc.Source;
				this.Installers.Add(logInstaller);
			}

			AppDomain.Unload(targetAppDomain);
		}
	}
}
